﻿using System;
using System.Collections.Generic;
using CrateMayhem.Common.Commanding;
using CrateMayhem.Common.Model;
using CrateMayhem.Common.Services;

namespace CrateMayhem.Common.ViewModel
{
    public class GameControlViewModel : ViewModelBase
    {
        private readonly IGameService gameService;
        private readonly IAutoCloseDialogService autoCloseDialogService;
        private readonly IMessageService messageService;
        private readonly Stack<MoveType> currentMoves = new Stack<MoveType>();
        private bool undoing;

        public GameControlViewModel(IServiceFactory serviceFactory)
        {
            gameService = serviceFactory.Create<IGameService>();
            autoCloseDialogService = serviceFactory.Create<IAutoCloseDialogService>();
            messageService = serviceFactory.Create<IMessageService>();

            gameService.PushCompleted += GameServiceOnPushCompleted;
            gameService.Finished += GameServiceOnFinished;
            MoveUpCommand = RegisterCommand(new DelegateCommand(() => Move(MoveType.Up)));
            MoveRightCommand = RegisterCommand(new DelegateCommand(() => Move(MoveType.Right)));
            MoveDownCommand = RegisterCommand(new DelegateCommand(() => Move(MoveType.Down)));
            MoveLeftCommand = RegisterCommand(new DelegateCommand(() => Move(MoveType.Left)));
            RetryCommand = RegisterCommand(new DelegateCommand(Retry));
            UndoCommand = RegisterCommand(new DelegateCommand(Undo));
        }

        private void GameServiceOnFinished(object sender, EventArgs eventArgs)
        {
            currentMoves.Clear();
        }

        private void GameServiceOnPushCompleted(object sender, PushCompletedEventArgs args)
        {
            if (!undoing && args.Pushed)
            {
                currentMoves.Push(args.Move);
            }
        }

        public DelegateCommand MoveUpCommand { get; private set; }
        public DelegateCommand MoveRightCommand { get; private set; }
        public DelegateCommand MoveDownCommand { get; private set; }
        public DelegateCommand MoveLeftCommand { get; private set; }
        public DelegateCommand RetryCommand { get; private set; }
        public DelegateCommand UndoCommand { get; private set; }

        public void Move(MoveType move)
        {
            gameService.RaisePush(move);
        }

        public void Retry()
        {
            autoCloseDialogService.Closed += OnRetryWindowClosed;
            autoCloseDialogService.ShowDialog(messageService.RandomRetry(), 2000);
        }

        public void Undo()
        {
            if (currentMoves.Count > 0)
            {
                undoing = true;
                var move = currentMoves.Pop();
                gameService.RaiseUndo(move);
                undoing = false;
            }
        }

        private void OnRetryWindowClosed(object sender, EventArgs e)
        {
            autoCloseDialogService.Closed -= OnRetryWindowClosed;
            gameService.RaiseRetry();
        }
    }
}
